#pragma once
#include <zGraphicsConfig.hpp>
#include <common.hpp>
#include <Math/Vector3.hpp>
#include <Math/Vector2.hpp>

namespace zzz {
typedef pair<Vector2f,int> DelaunayVertex;
typedef vector<DelaunayVertex> DelaunayVertexSet;

///////////////////
// DelaunayTriangle

class ZGRAPHICS_CLASS DelaunayTriangle : public Vector<3, const DelaunayVertex*> {
public:
  DelaunayTriangle(const DelaunayTriangle& tri)
  : Center_(tri.Center_), R_(tri.R_), R2_(tri.R2_), Vector<3, const DelaunayVertex*>(tri) {
  }

  DelaunayTriangle(const DelaunayVertex *p0, const DelaunayVertex *p1, const DelaunayVertex *p2)
  :Vector<3, const DelaunayVertex*>(p0, p1, p2) {
    SetCircumCircle();
  }

  using Vector<3,const DelaunayVertex*>::operator[];

  bool operator<(const DelaunayTriangle& tri) const {
    return Center_ < tri.Center_;
  }

  bool IsLeftOf(DelaunayVertexSet::const_iterator itVertex) const {
    // returns true if * itVertex is to the right of the DelaunayTriangle's circumcircle
    return itVertex->first.x() > (Center_.x() + R_);
  }

  bool CCEncompasses(DelaunayVertexSet::const_iterator itVertex) const {
    // Returns true if * itVertex is in the DelaunayTriangle's circumcircle.
    // A Vector2f exactly on the circle is also considered to be in the circle.

    // First check boundary box.
    Vector2f dist = itVertex->first - Center_;    // the distance between v and the circle center
    float dist2 = dist.LenSqr();    // squared
    return dist2 <= R2_;                // compare with squared radius
  }

protected:
  Vector2f Center_;        // center of circumcircle
  float R_;      // radius of circumcircle
  float R2_;      // radius of circumcircle, squared
  void SetCircumCircle();
};

typedef vector<DelaunayTriangle> DelaunayTriangleSet;

///////////////////
// DelaunayEdge

typedef Vector<2, const DelaunayVertex*> DelaunayEdge;
typedef set<DelaunayEdge> DelaunayEdgeSet;

///////////////////
// Delaunay

class ZGRAPHICS_CLASS Delaunay {
public:
  void Triangulate(const vector<Vector2f>& vertices, vector<Vector3i>& output);

private:
  // Calculate the Delaunay triangulation for the given set of vertices.
  void DoTriangulate(const DelaunayVertexSet& vertices, DelaunayTriangleSet& output);

  // Put the edges of the triangles in an edgeSet, eliminating double edges.
  // This comes in useful for drawing the triangulation.
  void TrianglesToEdges(const DelaunayTriangleSet& triangles, DelaunayEdgeSet& edges);
protected:
  void HandleEdge(const DelaunayVertex * p0, const DelaunayVertex * p1, DelaunayEdgeSet& edges);
};
};  // namespace zzz